<?php
/**
 * Get Keywords Action Helper
 * Accepts a block of text and returns a list of its most often-occuring words
 * to be used for keywords for meta or whatever else you may need it for.
 *
 * @package     Visi
 * @subpackage  Action Helpers
 * @author      Luke Visinoni <luke.visinoni@gmail.com>
 * @copyright   (c) 2010 Luke Visinoni <luke.visinoni@gmail.com>
 * @version     $Id$
 */
class Visi_Controller_Action_Helper_GetKeywords extends Zend_Controller_Action_Helper_Abstract {

    protected $_stopWords = array();
    /**
     * Pass in a filename of a file with each word on a new line
     */
    public function __construct($stopWordsFile) {
    
        $this->_stopWords = array_map(array('self', 'filterStopWords'), file($stopWordsFile));
    
    }
    
    public function direct($text, $percentile = null, $maxWords = null) {
    
        $words = w($text);
        $words = array_map(array('self', 'filterStopWords'), $words);
        $words = array_diff($words, $this->_stopWords);
        return $this->_getCommonWords($words, null, $maxWords);
    
    }
    
    /**
     * Find the top $percentile most common words
     * @todo this needs to reduce the percentile the larger the text is. When
     * there are tons of comments or when the post body is really long, the
     * keywords list gets really long too, and that's not what we want.
     */
    protected function _getCommonWords($words, $percentile = null, $maxWords = null) {
    
        if (is_null($percentile)) $percentile = 0.33;
        $total = count($words);
        $results = array();
        $common = array();
        $counts = array();
        foreach ($words as $word) {
            if (empty($word)) continue;
            if (!array_key_exists($word, $counts)) $counts[$word] = 0;
            $counts[$word]++;
        }
        foreach ($counts as $word => $count) {
            $percent = round((($count / $total) * 100), 4);
            $common[$word] = $percent;
        }
        arsort($common);
        // grab only the top $percentile results
        $top = (integer) (count($counts) * $percentile);
        if (!is_null($maxWords)) {
            if ($top > $maxWords) $top = $maxWords;
        }
        for ($i = 0; $i < $top; $i++) {
            $results[] = key($common);
            next($common);
        }
        return $results;
    }
    
    static public function filterStopWords($word) {
    
        return strtolower(preg_replace('~[^a-z0-9\']~i', '', $word));
    
    }

}